package interpreter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SymbolTable {

	private List<Map<String, Symbol>> scopes = new ArrayList<>();

	public SymbolTable() {
		pushScope();
	}

	public Symbol get(String name) {
		for (int i = scopes.size() - 1; i >= 0; i--)
			if (scopes.get(i).containsKey(name))
				return scopes.get(i).get(name);
		throw new UnknownVariableCannotBeFound(name);
	}

	@SuppressWarnings("serial")
	public class UnknownVariableCannotBeFound extends RuntimeException {
		private String name;

		public UnknownVariableCannotBeFound(String name) {
			super(name);
			this.name = name;
		}

		public String getName() {
			return name;
		}
	}

	public void put(Symbol symbol) {
		currentScope().put(symbol.getName(), symbol);
	}

	private Map<String, Symbol> currentScope() {
		return scopes.get(scopes.size() - 1);
	}

	public void pushScope() {
		scopes.add(new HashMap<String, Symbol>());
	}

	public void popScope() {
		scopes.remove(scopes.size() - 1);
	}

	public void set(String name, Object value) {
		for (int i = scopes.size() - 1; i >= 0; i--)
			if (scopes.get(i).containsKey(name)) {
				scopes.get(i).put(name, new Symbol(name, value));
				return;
			}
		throw new UnknownVariableCannotBeSet(name);
	}

	@SuppressWarnings("serial")
	public class UnknownVariableCannotBeSet extends RuntimeException {
		private String name;

		public UnknownVariableCannotBeSet(String name) {
			super(name);
			this.name = name;
		}

		public String getName() {
			return name;
		}
	}

}
